import json
from datetime import datetime

from decimal import Decimal

from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponseForbidden, HttpResponse
from django.http import JsonResponse
from django.shortcuts import render

# Create your views here.
from django.views import View
from django_redis import get_redis_connection
from django.db import transaction

from apps.areas.models import Address
from apps.goods.models import SKU
from apps.orders.models import OrderInfo, OrderGoods
from utils.response_code import RETCODE


class OrderInfoView(LoginRequiredMixin, View):
    def get(self, request, page_num):
        user = request.user
        page_orders = OrderInfo.objects.filter(user_id=user.id)
        total_page = len(page_orders)

        context = {
            # 每页显示的内容
            "page_orders": page_orders,
            # 总页数
            'total_page': total_page,
            # 当前页
            'page_num': page_num,
        }

        return render(request, 'user_center_order.html', context)


class OrderSettlementView(LoginRequiredMixin, View):
    def get(self, request):
        # 结算订单，结算订单是从Redis购物车中查询出被勾选的商品信息进行结算并展示。
        # 通过user.id查表，获取当前用户地址信息，user.addresses
        user = request.user
        try:
            addresses = Address.objects.filter(user=user, is_deleted=False)
        except:
            addresses = None

        carts_client = get_redis_connection("carts")
        carts_data = carts_client.hgetall(user.id)
        carts_dict = {}
        for key, value in carts_data.items():
            sku_id = int(key.decode())
            sku_dict = json.loads(value.decode())
            if sku_dict['selected']:
                carts_dict[sku_id] = sku_dict

        print(carts_dict)
        # 计算金额
        total_count = 0
        total_amount = Decimal(0.00)
        skus = SKU.objects.filter(id__in=carts_dict.keys())

        for sku in skus:
            sku.count = carts_dict[sku.id].get('count')
            sku.amount = sku.count * sku.price
            total_count += sku.count
            total_amount += sku.amount

        freight = Decimal('10.00')
        # 查询redis订单SKU信息，并查询SQL数据库，返回单价，计算总钱数

        context = {
            'addresses': addresses,
            'skus': skus,
            'total_count': total_count,
            'total_amount': total_amount,
            'freight': freight,
            'payment_amount': total_amount + freight,
            'default_address_id': user.default_address_id
        }

        return render(request, 'place_order.html', context)


class OrderCommitView(LoginRequiredMixin, View):
    """订单提交"""

    def post(self, request):
        """
            保存订单信息和订单商品信息,返回值：
            code	    状态码
            errmsg	    错误信息
            order_id	订单编号
        """
        try:
            json_dict = json.loads(request.body.decode())
        except Exception as e:
            settings.LOGGER.erro(e)
            return HttpResponseForbidden('不正确的请求')
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')
        if not all([address_id, pay_method]):
            return HttpResponseForbidden('缺少必传参数')
        try:
            address = Address.objects.get(id=address_id)
        except Exception:
            return HttpResponseForbidden('参数address_id错误')
        try:
            pay_method = int(pay_method)
        except Exception:
            return HttpResponseForbidden('参数pay_method错误')
        if pay_method not in [int(i) for k, i in OrderInfo.PAY_METHODS_ENUM.items()]:
            # k不使用，这样写便于扩充支付方式
            return HttpResponseForbidden('参数pay_method错误')
        if pay_method == OrderInfo.PAY_METHODS_ENUM['CASH']:
            return JsonResponse({'code': RETCODE.PARAMERR, 'errmsg': '暂不支持货到付款', 'order_id': ""})

        user = request.user
        order_id = datetime.now().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)

        with transaction.atomic():
            # 保存地点
            save_id = transaction.savepoint()
            try:
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal('0'),
                    freight=Decimal('10.00'),
                    pay_method=pay_method,
                    status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM[
                        'ALIPAY'] else
                    OrderInfo.ORDER_STATUS_ENUM['UNSEND']
                )

                redis_client = get_redis_connection('carts')
                carts_data = redis_client.hgetall(user.id)
                carts_dict = {}
                for key, value in carts_data.items():
                    sku_id = int(key.decode())
                    sku_dict = json.loads(value.decode())
                    if sku_dict['selected']:
                        carts_dict[sku_id] = sku_dict
                # 遍历 商品信息
                for sku_id in carts_dict:
                    # 默认就是遍历的key
                    # 这里作为事务的一部分，直接暴力回滚即可
                    while True:
                        # 之后才选择SKU，可以防止出现无法跳出的死循环
                        sku = SKU.objects.get(id=sku_id)

                        # 原始的销量和库存，用于乐观锁，需要更改SQL设置
                        origin_sales = sku.sales
                        origin_stock = sku.stock

                        cart_count = carts_dict[sku_id]['count']
                        # 判断库存是否充足
                        if cart_count > sku.stock:
                            transaction.savepoint_rollback(save_id)
                            return JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})

                        # sku减少库存, 增加销量
                        new_stock = origin_stock - cart_count
                        new_sales = origin_sales + cart_count
                        result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock,
                                                                                          sales=new_sales)
                        if result == 0:
                            # 说明啥也没修改，重新来过
                            continue
                        # SPU 增加销量
                        sku.spu.sales += cart_count
                        sku.spu.save()

                        # 保存订单商品信息
                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=cart_count,
                            price=sku.price,
                        )

                        # 保存商品订单中总价和总数量
                        order.total_count += cart_count
                        order.total_amount += (cart_count * sku.price)

                        break

                # 添加邮费和保存订单
                order.total_amount += order.freight
                order.save()
            except Exception:
                transaction.savepoint_rollback(save_id)
                return JsonResponse({'code': RETCODE.OK, 'errmsg': '下单失败'})

            transaction.savepoint_commit(save_id)

        # 清除购物车已经结算过的商品
        redis_client.hdel(user.id, *carts_dict)

        # 返回响应结果
        return JsonResponse({'code': RETCODE.OK, 'errmsg': '下单成功', 'order_id': order.order_id})


class OrderSuccessView(LoginRequiredMixin, View):
    """提交订单成功"""

    def get(self, request):
        order_id = request.GET.get('order_id')
        payment_amount = request.GET.get('payment_amount')
        pay_method = request.GET.get('pay_method')

        context = {
            'order_id': order_id,
            'payment_amount': payment_amount,
            'pay_method': pay_method
        }
        return render(request, 'order_success.html', context)
